#ifndef VECTOR2_H
#define VECTOR2_H

#include "Math/Math.h"

namespace tyro
{
	namespace Math
	{

		/* Forward declare Vector 3 */
		template <class T>
		class Vector3;

		template <class T>
		class Vector2
		{
		public:

			/* Default Constructor */
			Vector2<T>() : x(0), y(0){}

			/* Multi-Contructors */
			inline		Vector2<T>( T _x, T _y ) : x( _x ), y( _y ) {}
			inline		Vector2<T>( const T* vec ) : x( vec[ 0 ] ), y( vec[ 1 ] ) {}

			/* Operator Overloaders */

			/* Casting Operators*/
			inline 					operator T* ();
			inline 					operator const T* () const;

			/* Assignment Operators */
			inline Vector2<T>&		operator = ( const Vector2<T>& vec );
			Vector2<T>&		operator = ( const Vector3<T>& vec );

			/* Relational and Equality Operators */
			inline	bool			operator == ( const Vector2<T>& vec ) const;
			inline	bool			operator != ( const Vector2<T>& vec ) const;

			/* Binary Arithmetic Operators */
			inline const Vector2<T> operator - () const;
			inline const Vector2<T> operator - ( const Vector2<T>& vec ) const;
			inline const Vector2<T> operator + ( const Vector2<T>& vec ) const;
			inline const Vector2<T>	operator + () const;
			inline Vector2<T>&		operator + ( const T value );
			inline const Vector2<T> operator * ( T value ) const;
			inline T				operator * ( const Vector2<T>& vec ) const;
			inline const Vector2<T> operator / ( T value ) const;

			//----------------------------------------------------------------------------- 
			// Friend Scalar Multiplication
			//-----------------------------------------------------------------------------
			inline friend const Vector2<T> operator * ( T value, const Vector2<T>& vec )
			{
				return vec * value;
			}

			/* Compound Assignment Operators */
			inline	Vector2<T>&		operator += ( const Vector2<T>& vec );
			inline	Vector2<T>&		operator -= ( const Vector2<T>& vec );
			inline	Vector2<T>&		operator += ( const T value );
			inline	Vector2<T>&		operator *= ( T value );
			inline	Vector2<T>&		operator /= ( T value );


			/* Conditional Operator */
			/* Comma Operator */
			/* Bitwise Operators */

			/* Getter and Setter */
			inline void			Set(T _x, T _y);
			inline void			Get(T& _x, T& _y);

			
			inline void			Zero();
			inline T			Magnitude() const;
			inline T			MagnitudeSquared() const;

			/* Vector 2 data members */
			T x;
			T y;

			/* Constants */
			static const Vector2<T> ZERO;

		};

		//----------------------------------------------------------------------------- 
		// Casting Operator
		//-----------------------------------------------------------------------------
		template <class T>
		inline Vector2<T>::operator T* ()
		{
			return reinterpret_cast<T*>(this);
		}

		//----------------------------------------------------------------------------- 
		// Const Casting Operator
		//-----------------------------------------------------------------------------
		template <class T>
		inline Vector2<T>::operator const T* () const
		{
			return reinterpret_cast<const T*>(this);
		}

		//----------------------------------------------------------------------------- 
		// Assignment Operator
		//-----------------------------------------------------------------------------
		template <class T>
		inline Vector2<T>& Vector2<T>::operator = ( const Vector2<T>& vec )
		{
			x = vec.x;
			y = vec.y;
			return *this;
		}

		

		//----------------------------------------------------------------------------- 
		// Equal to
		//-----------------------------------------------------------------------------
		template <class T>
		inline bool Vector2<T>::operator == ( const Vector2<T>& vec ) const
		{
			return ( x == vec.x && y == vec.y );
		}

		//----------------------------------------------------------------------------- 
		// Not Equal to
		//-----------------------------------------------------------------------------
		template <class T>
		inline bool Vector2<T>::operator != ( const Vector2<T>& vec ) const
		{
			return (x != vec.x && y != vec.y );
		}

		//----------------------------------------------------------------------------- 
		// Unary minus
		//-----------------------------------------------------------------------------
		template <class T>
		inline const Vector2<T> Vector2<T>::operator - () const
		{
			return Vector2<T>( -x, -y );
		}

		//----------------------------------------------------------------------------- 
		// Subtraction
		//-----------------------------------------------------------------------------
		template <class T>
		inline const Vector2<T> Vector2<T>::operator - ( const Vector2<T>& vec ) const
		{
			return Vector2<T>( x - vec.x, y - vec.y );
		}

		//----------------------------------------------------------------------------- 
		// Addition
		//-----------------------------------------------------------------------------
		template <class T>
		inline const Vector2<T> Vector2<T>::operator + ( const Vector2<T>& vec ) const
		{
			return Vector2<T>( x + vec.x, y + vec.y );
		}

		//----------------------------------------------------------------------------- 
		// Unary plus
		//-----------------------------------------------------------------------------
		template <class T>
		inline const Vector2<T> Vector2<T>::operator + () const
		{
			return Vector2<T>( +x, +y );
		}

		//----------------------------------------------------------------------------- 
		// Addition
		//-----------------------------------------------------------------------------
		template <class T>
		inline Vector2<T>& Vector2<T>::operator + ( const T value )
		{
			x += value;
			y += value;
			return *this;
		}

		//----------------------------------------------------------------------------- 
		// Scalar Multiplication
		//-----------------------------------------------------------------------------
		template <class T>
		inline const Vector2<T> Vector2<T>::operator * ( T value ) const
		{
			return Vector2<T>( x * value, y * value ); 
		}

		//----------------------------------------------------------------------------- 
		// Dot product
		//-----------------------------------------------------------------------------
		template <class T>
		inline T Vector2<T>::operator * ( const Vector2<T>& vec ) const
		{
			return ( x * vec.x + y * vec.y ); 
		}

		//----------------------------------------------------------------------------- 
		// Scalar Division
		//-----------------------------------------------------------------------------
		template <class T>
		inline const Vector2<T> Vector2<T>::operator / ( T value ) const
		{
			const T reciprocal = 1.0f / value;
			return Vector2<T>( x * reciprocal, y * reciprocal );
		}

		//----------------------------------------------------------------------------- 
		// Addition Assignment
		//-----------------------------------------------------------------------------
		template <class T>
		inline Vector2<T>& Vector2<T>::operator += ( const Vector2<T>& vec )
		{
			x += vec.x;
			y += vec.y;
			return *this;
		}

		//----------------------------------------------------------------------------- 
		// Subtraction Assignment
		//-----------------------------------------------------------------------------
		template <class T>
		inline Vector2<T>& Vector2<T>::operator -= ( const Vector2<T>& vec )
		{
			x -= vec.x;
			y -= vec.y;
			return *this;
		}

		//----------------------------------------------------------------------------- 
		// Addition Assignment
		//-----------------------------------------------------------------------------
		template <class T>
		inline Vector2<T>& Vector2<T>::operator += ( const T value )
		{
			x += value;
			y += value;
			return *this;
		}

		//----------------------------------------------------------------------------- 
		// Multiplication Assignment
		//-----------------------------------------------------------------------------
		template <class T>
		inline Vector2<T>& Vector2<T>::operator *= ( T value )
		{
			x *= value;
			y *= value;
			return *this;
		}

		//----------------------------------------------------------------------------- 
		// Division Assignment
		//-----------------------------------------------------------------------------
		template <class T>
		inline Vector2<T>& Vector2<T>::operator /= ( T value )
		{
			const T reciprocal = 1.0f / value;
			x *= reciprocal;
			y *= reciprocal;
			return *this;
		}


		

		//----------------------------------------------------------------------------- 
		// Setter
		//-----------------------------------------------------------------------------
		template <class T>
		inline void Vector2<T>::Set(T _x, T _y)
		{
			x = _x;
			y = _y;
		}

		//----------------------------------------------------------------------------- 
		// Getter
		//-----------------------------------------------------------------------------
		template <class T>
		inline void	Vector2<T>::Get(T& _x, T& _y)
		{
			_x = x;
			_y = y;
		}

		//----------------------------------------------------------------------------- 
		// Zero Vector
		//-----------------------------------------------------------------------------
		template <class T>
		inline void	Vector2<T>::Zero()
		{
			x = y = 0.0f;
		}

		//----------------------------------------------------------------------------- 
		// Maginitude
		//-----------------------------------------------------------------------------
		template <class T>
		inline T Vector2<T>::Magnitude() const
		{
			return (T)sqrt((T) x * x + y * y );
		}

		//----------------------------------------------------------------------------- 
		// Squared Maginitude
		//-----------------------------------------------------------------------------
		template <class T>
		inline T Vector2<T>::MagnitudeSquared() const
		{
			return ( x * x + y * y );
		}



		

	}
}



#endif